﻿using AvoidForgettingApi.Entities.Models;
using AvoidForgettingApi.JWT;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;

namespace JWTToken.Filter
{
    /// <summary>
    /// Token过滤器
    /// </summary>
    public class TokenFilter : Attribute, IActionFilter
    {
        private ITokenHelper tokenHelper;

        /// <summary>
        /// 获取配置文件类
        /// </summary>
        public IConfiguration Configuration { get; }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="_tokenHelper"></param>
        /// <param name="_configuration"></param>
        public TokenFilter(ITokenHelper _tokenHelper, IConfiguration _configuration) //通过依赖注入得到数据访问层实例
        {
            Configuration = _configuration;
            tokenHelper = _tokenHelper;
           
        }

        /// <summary>
        /// 执行完成
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {


            string tokenName = Configuration.GetSection("JWTConfig").GetSection("tokenName").Value;
            int WaringMinutes = int.Parse(Configuration.GetSection("JWTConfig").GetSection("WaringMinutes").Value);
            string Issuer = Configuration.GetSection("JWTConfig").GetSection("Issuer").Value;
            string Audience = Configuration.GetSection("JWTConfig").GetSection("Audience").Value;

            bool HasToken = context.HttpContext.Request.Headers.TryGetValue(tokenName, out var tokenobj);
            string token = tokenobj.ToString();
            var ret = new CommonResponse();
            string usercode = "";
            DateTime createTime = new DateTime();
            TokenType tokenType = tokenHelper.ValiTokenState(token, a => a["iss"] == Issuer && a["aud"] == Audience, action =>
            {
                usercode = action["usercode"];
                createTime = DateTime.Parse(action["createTime"]);
            });

            TokenInfo TokenInfo = null;
            if (createTime.AddMinutes(WaringMinutes) <= DateTime.Now)
            {
                TokenInfo = tokenHelper.CreateToken(new Dictionary<string, object>
                    {
                        { "usercode", usercode },
                        { "createTime", DateTime.Now}
                    });
            }

            if (context.Result is OkObjectResult)
            {
                var data = context.Result as OkObjectResult;
                context.Result = new OkObjectResult(new CommonResponse
                {
                    Code = 0,
                    Message = "",
                    TokenInfo = TokenInfo,
                    Data = data.Value
                });
            }

            if (context.Result is BadRequestObjectResult)
            {
                var data = context.Result as BadRequestObjectResult;
                context.Result = new BadRequestObjectResult(new CommonResponse
                {
                    Code = -1,
                    Message = data.Value.ToString()
                });
            }
        }


        public class ValidationError
        {
            [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
            public string Field { get; }
            public string Message { get; }
            public ValidationError(string field, string message)
            {
                Field = field != string.Empty ? field : null;
                Message = message;
            }
        }

        /// <summary>
        /// 执行之前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {

            CommonResponse ret = new CommonResponse();
            try
            {
                //var methodinfo = context.ActionDescriptor.ActionConstraints[0] as Microsoft.AspNetCore.Mvc.ActionConstraints.HttpMethodActionConstraint;
                //var actionType = new List<string>(methodinfo.HttpMethods);
                //var requestType = context.HttpContext.Request.Method;

                //if (actionType[0] != requestType)
                //{
                //    ret.errcode = -1;
                //    ret.errmsg = $"不允许用{requestType}请求{actionType}api";
                //    context.Result = new BadRequestObjectResult(ret);
                //    return;
                //}

                string tokenName = Configuration.GetSection("JWTConfig").GetSection("tokenName").Value;
                int WaringMinutes = int.Parse(Configuration.GetSection("JWTConfig").GetSection("WaringMinutes").Value);
                string Issuer = Configuration.GetSection("JWTConfig").GetSection("Issuer").Value;
                string Audience = Configuration.GetSection("JWTConfig").GetSection("Audience").Value;
                if (context.HttpContext.Request.Path.Value.ToLower() != "/api/user/login")
                {
                    //获取token
                    bool HasToken = context.HttpContext.Request.Headers.TryGetValue(tokenName, out var tokenobj);

                    if (!HasToken)
                    {
                        ret.Code = -2;
                        ret.Message = "token不能为空";
                        context.Result = new UnauthorizedObjectResult(ret);
                        return;
                    }

                    string token = tokenobj.ToString();

                    string usercode = "";
                    DateTime createTime = new DateTime();

                    //验证jwt,同时取出来jwt里边的用户ID
                    TokenType tokenType = tokenHelper.ValiTokenState(token, a => a["iss"] == Issuer && a["aud"] == Audience, action =>
                    {
                        usercode = action["usercode"];
                        createTime = DateTime.Parse(action["createTime"]);
                    });
                    if (tokenType == TokenType.Fail)
                    {
                        ret.Code = -2;
                        ret.Message = "token验证失败";
                        context.Result = new UnauthorizedObjectResult(ret);
                        return;
                    }
                    if (tokenType == TokenType.Expired)
                    {
                        ret.Code = -2;
                        ret.Message = "token已经过期";
                        context.Result = new UnauthorizedObjectResult(ret);
                        return;
                    }

                    if (!context.ModelState.IsValid)
                    {
                        ret.Data = context.ModelState.Keys
                                .SelectMany(key => context.ModelState[key].Errors.Select(x => new ValidationError(key, x.ErrorMessage)))
                                .ToList();

                        ret.Code = -2;
                        ret.Message = "入参不合法,请根据data中数据进行检查!";
                        context.Result = new BadRequestObjectResult(ret);
                        return;
                    }

                    if (!string.IsNullOrEmpty(usercode))
                    {
                        context.ActionArguments.Add("usercode", usercode);
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                ret.Code = -1;
                ret.Message = "服务器内部错误";
                ret.Data = ex;
                context.Result = new UnprocessableEntityObjectResult(ret);
                return;
            }
                   
        }
    }
}